#!/usr/bin/env python
#-IMPORTS-----------------------------------------------------------------------
import os
import sys
import time
import async
import Queue
import worker
import logging
import cmdline
import threading
#-CLASSES-----------------------------------------------------------------------
class ThreadManager:
    def __init__(self, p_cmgr = None):
        self.__log = logging.getLogger(__name__)
        self.__cmgr = p_cmgr
        self.__job_queue = Queue.Queue()
        self.__results_queue = Queue.Queue()
        if p_cmgr is None:
            self.__log.error('No command manager passed in, cannot continue, exiting...')
            sys.exit(-1)

    def __create_pool(self, p_num):
        for x in range(p_num):
            worker.Worker(self.__job_queue, self.__results_queue, self.__cmgr).start()

    def __run_synchronous(self):
        for cmd in self.__cmgr.waiting:
            exe = cmd.s_cmd.split(' ')
            cmd.timeout = time.time() + (float(cmdline.options.timeout)-1)
            cmd.proc = async.Popen(exe,
                                   stdin = async.PIPE,
                                   stdout = async.PIPE,
                                   stderr = async.PIPE,
                                   env = os.environ,
                                   preexec_fn = cmd._pre_execute_())
            while cmd.proc.poll() is None:
                if time.time() > cmd.timeout:
                    cmd.timedout = True
                    break
                time.sleep(0.1)
            self.__get_output(cmd)
            cmd.retcode = cmd.proc.returncode
            cmd._post_execute_()
            if cmd.retcode:
                self.__cmgr.completed_error.append(cmd)
            else:
                self.__cmgr.completed_success.append(cmd)
                if cmdline.options.wait:
                    self.__log.debug('Waiting for %s seconds.'%cmdline.options.wait)
                    time.sleep(float(cmdline.options.wait))

    def __run_asynchronous(self):
        #Load the job queue
        num_cmd = len(self.__cmgr.waiting)
        self.__create_pool(num_cmd)
        for cmd in self.__cmgr.waiting:
            self.__job_queue.put(cmd)
            self.__job_queue.put(None) #End-of-job markers
        #Wait for all workers to end
        if num_cmd != 1:
            while threading.activeCount() >= num_cmd:
                time.sleep(0.01)
        else:
            while threading.activeCount() > num_cmd:
                time.sleep(0.01)

    def run(self):
        self.__log.info('Preparing %d command(s) for processing.'%len(self.__cmgr.waiting))
        if cmdline.options.sequential:
            self.__log.info('Synchronous processing.')
            self.__run_synchronous()
        else:
            self.__log.info('Asynchronous processing.')
            self.__run_asynchronous()
        self.__log.info('Total=%d command(s): %d successful; %d error(s).'%(len(self.__cmgr.completed_success) + len(self.__cmgr.completed_error),
                                                                            len(self.__cmgr.completed_success),
                                                                            len(self.__cmgr.completed_error)))
